package com.Sdebruijn.curriculumvitae.view;

import java.io.File;

import roboguice.util.Ln;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.Sdebruijn.curriculumvitae.sync.remote.DownloadListener;
import com.Sdebruijn.curriculumvitae.sync.remote.DownloadTask;
import com.Sdebruijn.curriculumvitae.util.StorageUtil;

/**
 * Utility class opening an image from a {@link String} URL into an
 * {@link ImageView}
 */
public class RemoteImageView extends ImageView {

	/** Keeps count when failing to download/load the image */
	private int failedCount = 0;

	/** Maximum amount of fails before aborting */
	private static final int MAX_FAILED_COUNT = 4;

	/** Local path to the cache dir */
	private String localPath;

	/** String representing the URL to download the image from */
	private String remoteUrl;

	/** Indicating whether we have an image */
	private boolean hasImage;

	/** The bitmap to fill */
	private Bitmap imageViewBitmap;

	/**
	 * Instantiates a new remote image view.
	 * 
	 * @param context
	 *            the context
	 * @param attrs
	 *            the attrs
	 */
	public RemoteImageView(final Context context, final AttributeSet attrs) {
		this(context, attrs, 0);
	}

	/**
	 * Instantiates a new remote image view.
	 * 
	 * @param context
	 *            the context
	 * @param attrs
	 *            the attrs
	 * @param defStyle
	 *            the def style
	 */
	public RemoteImageView(final Context context, final AttributeSet attrs,
			final int defStyle) {
		super(context, attrs, defStyle);
	}

	/**
	 * Sets the remote path.
	 * 
	 * @param remote
	 *            the new remote path
	 */
	public void setRemotePath(final String remote) {
		this.remoteUrl = remote;
	}

	/**
	 * Sets the local path.
	 * 
	 * @param local
	 *            the new local path
	 */
	public void setLocalPath(final String local) {
		this.localPath = local;
	}

	/**
	 * Load an image from an URL
	 * 
	 * @param needsHighPriority
	 *            boolean indicating if this has the highest priority
	 */
	public void loadImage(final boolean needsHighPriority) {
		if (remoteUrl != null) {

			// check for the local file here instead of in the thread because
			// otherwise previously-cached files wouldn't be loaded until after
			// the remote ones have been downloaded.

			if (localPath == null) {
				localPath = StorageUtil.getBestCachePath(getContext())
						+ "/temp/" + remoteUrl.hashCode() + ".jpg";
			}
			File localFile = new File(localPath);

			if (localFile.exists()) {
				Ln.d("Image found on local storage : [" + localPath + "]");
				if (needsHighPriority) {
					queue(DownloadTask.Priority.HighHead);
				} else {
					queue(DownloadTask.Priority.HighTail);
				}

			} else {
				// we already have the local reference, so just make the parent
				// directories here instead of in the thread.
				localFile.getParentFile().mkdirs();

				Ln.i("Image not found on local storage. Start download!");
				queue(DownloadTask.Priority.HighTail);
			}
		} else {
			throw new IllegalArgumentException(
					"You must set the remote and local paths!");
		}
	}

	/**
	 * Queue.
	 * 
	 * @param p
	 *            {@link DownloadTask.Priority} indicating the priority in the queue.
	 */
	private void queue(final DownloadTask.Priority p) {
		DownloadTask downloader = DownloadTask.getInstance(getContext());

		downloader.enqueue(remoteUrl, localPath, new DownloadListener() {

			@Override
			public void failed() {
				failedCount++;

				if (failedCount < MAX_FAILED_COUNT) {
					queue(p);
				}
			}

			@Override
			public void onSucces(final Bitmap bmp, final String local) {
				setFromLocal(bmp);
			}

		}, DownloadTask.Type.Image, p);
	}

	/**
	 * Sets the from local.
	 * 
	 * @param bitmap
	 *            the new from local
	 */
	private void setFromLocal(final Bitmap bitmap) {
		if (!hasImage) {
			if (bitmap != null) {
				((Activity) getContext()).runOnUiThread(new Runnable() {
					public void run() {
						setImageBitmap(bitmap);
					}
				});

				this.imageViewBitmap = bitmap;
				hasImage = true;
			}
		}
	}

	/**
	 * Clear image bitmap
	 */
	public void clearImage() {
		this.setImageBitmap(null);

		if (imageViewBitmap != null) {
			imageViewBitmap.recycle();
		}

		hasImage = false;
	}
}
